package com.example.demo.utils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Locale;

public class SecurityUtils {
    public static final String ENCODE = "UTF-8";
    public static final String CIPHER_ALGORITHM = "AES/ECB/PKCS7Padding";

    private SecurityUtils() {
    }

    public static byte[] initAES256Key() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(256);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    public static byte[] initHmacSHA256Key() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA256");
        keyGenerator.init(256);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey.getEncoded();
    }

    public static byte[] encodeHmacSHA256(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {
        SecretKey secretKey = new SecretKeySpec(key, "HmacSHA256");
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        return mac.doFinal(data);
    }

    public static String encodeHmacSHA256HexUpper(String data, byte[] key) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException {
        return bytesToHexString(encodeHmacSHA256(data.getBytes("UTF-8"), key)).toUpperCase(Locale.US);
    }

    public static byte[] encrypt(byte[] data, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(1, new SecretKeySpec(key, "AES"));
        return cipher.doFinal(data);
    }

    public static byte[] decrypt(byte[] data, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(2, new SecretKeySpec(key, "AES"));
        return cipher.doFinal(data);
    }

    public static String encodeHexUpper(byte[] data) throws UnsupportedEncodingException {
        return bytesToHexString(data).toUpperCase(Locale.US);
    }

    public static byte[] decodeHexUpper(String str) throws UnsupportedEncodingException {
        return Hex.decode(str.toLowerCase(Locale.US));
    }

    public static String decodeHexUpper(String str, String charsetName) throws UnsupportedEncodingException {
        return new String(Hex.decode(str.toLowerCase(Locale.US)), charsetName);
    }

    public static String encodeAES256HexUpper(String data, byte[] key) throws UnsupportedEncodingException, IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
        return encodeHexUpper(encrypt(data.getBytes("UTF-8"), key));
    }

    public static String decodeAES256HexUpper(String data, byte[] key) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException {
        return new String(decrypt(Hex.decode(data.toLowerCase(Locale.US)), key), "UTF-8");
    }

    public static String bytesToHexString(byte[] b) {
        StringBuilder sb = new StringBuilder();
        for (byte b2 : b) {
            String hex = Integer.toHexString(b2 & 255);
            if (hex.length() == 1) {
                hex = String.valueOf('0') + hex;
            }
            sb.append(hex);
        }
        return sb.toString();
    }


}
